package com.buli.util.winSw;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;


import com.buli.util.logger.LoggerUtils;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * 服务配置类
 * 该类用于存储与服务相关的配置信息，包括WinSW执行文件路径、配置文件路径和备份路径
 */
public class ServiceConfigurationUtil {
    // Logger实例，用于日志记录
    private static final java.util.logging.Logger logs = java.util.logging.Logger.getLogger(ServiceConfigurationUtil.class.getName());
    // WinSW执行文件路径，用于定义服务的可执行文件位置
    private static final String WIN_SW_EXE_PATH = "E:\\tools\\Development\\WinSW\\WINSW.exe";

    // 全局变量，用于存储备份好的 EXE 文件路径
    public static String backupExePath;

    // 备份路径，用于存储服务配置的备份文件
    private static final String BACKUP_PATH = "E:\\tools\\Development\\WinSW\\config\\backup\\";



    /**
     * 配置服务使用WinSW（Windows Service Wrapper）
     * 该方法创建一个XML配置文件，用于在Windows上作为服务运行的可执行文件
     * 它处理服务的启动，日志记录和其他配置细节
     *
     * @param serviceName        服务名称，用作XML文件中的id属性
     * @param serviceDisplayName 服务显示名称，用作XML文件中的name属性
     * @param serviceDescription 服务描述，包含在XML文件的description元素中
     * @param executablePath     可执行文件的路径，用于运行服务
     * @param logPath            日志文件的路径，用于存储服务日志
     */
    public static void configureService(String serviceName, String serviceDisplayName, String serviceDescription,
                                        String executablePath, String logPath) {
        try {
            // 创建一个新的DocumentBuilderFactory实例
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            // 使用工厂创建一个新的DocumentBuilder
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            // 创建一个新的Document对象
            Document doc = docBuilder.newDocument();

            // 根元素
            Element rootElement = doc.createElement("service");
            doc.appendChild(rootElement);

            // 添加 id 元素
            Element idElement = doc.createElement("id");
            idElement.appendChild(doc.createTextNode(serviceName));
            rootElement.appendChild(idElement);

            // 添加注释
            Comment idComment = doc.createComment("服务的唯一标识符");
            rootElement.appendChild(idComment);

            // 添加 name 元素
            Element nameElement = doc.createElement("name");
            nameElement.appendChild(doc.createTextNode(serviceDisplayName));
            rootElement.appendChild(nameElement);

            // 添加注释
            Comment nameComment = doc.createComment("服务的显示名称");
            rootElement.appendChild(nameComment);

            // 添加 description 元素
            Element description = doc.createElement("description");
            description.appendChild(doc.createTextNode(serviceDescription));
            rootElement.appendChild(description);

            // 添加注释
            Comment descriptionComment = doc.createComment("服务的描述");
            rootElement.appendChild(descriptionComment);

            // 添加 runner 元素
            Element runner = doc.createElement("executable");
            runner.appendChild(doc.createTextNode(executablePath));
            rootElement.appendChild(runner);


            // 添加注释
            Comment runnerComment = doc.createComment("Nacos 启动脚本的路径");
            rootElement.appendChild(runnerComment);

            // 添加 logger 元素
            Element loggerElement = doc.createElement("logger");
            loggerElement.setAttribute("mode", "roll-by-size-time");

            // 添加 logpath 元素
            Element logpath = doc.createElement("logpath");
            logpath.appendChild(doc.createTextNode(logPath));
            loggerElement.appendChild(logpath);

            // 添加注释
            Comment logpathComment = doc.createComment("日志路径");
            loggerElement.appendChild(logpathComment);

            // 添加 sizeThreshold 元素
            Element sizeThreshold = doc.createElement("sizeThreshold");
            sizeThreshold.appendChild(doc.createTextNode("10240"));
            loggerElement.appendChild(sizeThreshold);

            // 添加注释
            Comment sizeThresholdComment = doc.createComment("设置日志模式为按文件大小和时间滚动");
            loggerElement.appendChild(sizeThresholdComment);

            // 添加 pattern 元素
            Element pattern = doc.createElement("pattern");
            pattern.appendChild(doc.createTextNode("yyyyMMdd"));
            loggerElement.appendChild(pattern);

            // 添加注释
            Comment patternComment = doc.createComment("设置日志文件名按时间的格式");
            loggerElement.appendChild(patternComment);

            // 添加 autoRollAtTime 元素
            Element autoRollAtTime = doc.createElement("autoRollAtTime");
            autoRollAtTime.appendChild(doc.createTextNode("00:00:00"));
            loggerElement.appendChild(autoRollAtTime);

            // 添加注释
            Comment autoRollAtTimeComment = doc.createComment("设置每天按时间滚动日志的时间");
            loggerElement.appendChild(autoRollAtTimeComment);

            // 添加 zipOlderThanNumDays 元素
            Element zipOlderThanNumDays = doc.createElement("zipOlderThanNumDays");
            zipOlderThanNumDays.appendChild(doc.createTextNode("5"));
            loggerElement.appendChild(zipOlderThanNumDays);

            // 添加注释
            Comment zipOlderThanNumDaysComment = doc.createComment("文件保留天数(需要autoRollAtTime同时使用)");
            loggerElement.appendChild(zipOlderThanNumDaysComment);

            // 添加 zipDateFormat 元素（可选）
            Element zipDateFormat = doc.createElement("zipDateFormat");
            zipDateFormat.appendChild(doc.createTextNode("yyyyMMdd"));
            loggerElement.appendChild(zipDateFormat);

            // 添加注释
            Comment zipDateFormatComment = doc.createComment("设置日志压缩文件的日期格式");
            loggerElement.appendChild(zipDateFormatComment);

            // 添加 logger 元素到 rootElement
            rootElement.appendChild(loggerElement);

            // 添加注释
            Comment loggerComment = doc.createComment("日志配置");
            rootElement.appendChild(loggerComment);


            saveAndBackupXmlAndExe(doc, serviceName);

            // 检查服务是否存在
            boolean serviceExists = checkServiceExists(serviceName);
            if (serviceExists) {
                sleep();
                try {
                    // 停止服务
                    stopService(serviceName);
                } catch (Exception e) {
                    LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Failed to stop service {}: ", serviceName, e);
                    return;
                }
                sleep();

                try {
                    // 移除服务
                    UnInstallService(serviceName);
                } catch (Exception e) {
                    LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Failed to uninstall service {}: ", serviceName, e);
                    return;
                }
            }

            sleep();
            try {
                // 安装服务
                installService(serviceName);
            } catch (Exception e) {
                LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Failed to install service {}: ", serviceName, e);
                return;
            }
            sleep();
            try {
                // 启动服务
                startService(serviceName);
            } catch (Exception e) {
                LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Failed to start service {}: ", serviceName, e);
                return;
            }
            LoggerUtils.info("Backup WinSW configuration file generated successfully at path: {}", BACKUP_PATH + serviceName + ".xml");
            LoggerUtils.info("Service {} installed successfully.", serviceName);
        } catch (Exception e) {
            LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Error generating WinSW configuration file: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to generate WinSW configuration file", e);
        } finally {
         /*   Connection connection = getConnection();
            if (connection != null) {

                // CreateTable.createTable(connection);
                //insertServiceData(connection, serviceName, serviceDisplayName, serviceDescription, executablePath, logPath);
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }*/
        }
    }

    private static void saveAndBackupXmlAndExe(Document doc, String serviceName) throws Exception {
        // 保存 XML 文件
        File mainOutputFile = new File(BACKUP_PATH + serviceName + ".xml");
        if (mainOutputFile.exists()) {
            
            LoggerUtils.logWithLocation(LoggerUtils.LogLevel.DEBUG,"Deleting existing file: {}", BACKUP_PATH + serviceName + ".xml");
            mainOutputFile.delete();
        }

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult mainResult = new StreamResult(mainOutputFile);
        transformer.transform(source, mainResult);

        // 备份 EXE 文件
        Path sourcePath = Paths.get(WIN_SW_EXE_PATH);
        Path targetPath = Paths.get(BACKUP_PATH + serviceName + ".exe");

        if (Files.exists(sourcePath) && Files.isRegularFile(sourcePath)) {
            if (!Files.exists(targetPath)) {
                Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
                LoggerUtils.logWithLocation("EXE file backed up to: {}", targetPath);
                // 更新全局变量
                backupExePath = targetPath.toString();
            } else {
                LoggerUtils.logWithLocation("EXE file already exists at: {}", targetPath);
                // 更新全局变量
                backupExePath = targetPath.toString();
            }
        } else {
            LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Source EXE file does not exist or is not a regular file: {}", WIN_SW_EXE_PATH);
        }
    }

    private static void sleep() {
        // 等待几秒钟
        try {
            Thread.sleep(5000); // 等待5秒钟
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            LoggerUtils.logWithLocation(LoggerUtils.LogLevel.ERROR,"Interrupted while waiting between stopping and uninstalling service: ", e);
        }
    }





    /**
     * 检查服务是否已启动
     * 通过执行特定的进程命令来检查服务的状态，并根据返回的结果判断服务是否已成功启动
     *
     * @param serviceName 服务名称，用于标识服务
     * @return 返回一个布尔值，表示服务是否已启动
     * <p>
     * 注意：这个方法使用了硬编码的字符串backupExePath和CONFIG_PATH，这可能会影响代码的灵活性和可维护性
     * 另外，这个方法处理了IOException和InterruptedException异常，表明它执行了一个可能阻塞的进程操作
     */
    private static boolean checkServiceExists(String serviceName) {
        try {
            // 执行服务状态检查命令，并获取结果映射
            Map<String, Object> map = executeProcess(backupExePath + " status ", serviceName);
            // 检查命令执行的返回码和输出消息，以确定服务是否已启动
            if ((Integer) map.get("code") == 0 && (map.get("msg").toString().contains("Started") || map.get("msg").toString().contains("Stopped"))) {
                // 如果服务已启动（无论是运行中还是已停止），则记录成功信息并返回true
                LoggerUtils.info("Service {} statused successfully.", serviceName, map.get("msg"));
                return true;
            } else {
                // 如果服务启动失败，则记录错误信息并返回false
                LoggerUtils.warn("Failed to status service {}: Exit code {}", serviceName, map.get("msg"));
                return false;
            }

        } catch (IOException | InterruptedException e) {
            // 异常情况下，记录严重错误信息，并返回false
            logs.log(Level.SEVERE, "Error checking service existence: ", e);
            return false;
        }
    }


    /**
     * 安装Windows服务
     * <p>
     * 该方法负责在系统中安装一个Windows服务它通过执行一个外部进程来完成实际的安装操作
     * 如果服务安装成功，它会在日志中记录成功信息；如果安装失败，则会记录警告信息
     * 如果在安装过程中遇到IOException或InterruptedException，则会记录严重错误信息
     *
     * @param serviceName 服务名称，用于标识服务并进行安装操作
     */
    private static void installService(String serviceName) {
        try {
            // 执行安装服务的外部进程，并获取进程返回的结果映射
            Map<String, Object> map = executeProcess(backupExePath + " install ", serviceName);
            // 检查进程返回码是否为0，以确定服务是否安装成功
            if ((Integer) map.get("code") == 0) {
                LoggerUtils.info("Service {} installed successfully.", serviceName, map.get("msg"));
            } else {
                // 如果安装失败，记录失败信息和退出码
                LoggerUtils.warn("Failed to install service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            // 如果发生IOException或InterruptedException，记录严重错误信息
            logs.log(Level.SEVERE, "Error installing service: ", e);
        }
    }

    /**
     * 移除Windows服务
     * <p>
     * 该方法负责在系统中安装一个Windows服务它通过执行一个外部进程来完成实际的安装操作
     * 如果服务安装成功，它会在日志中记录成功信息；如果安装失败，则会记录警告信息
     * 如果在安装过程中遇到IOException或InterruptedException，则会记录严重错误信息
     *
     * @param serviceName 服务名称，用于标识服务并进行安装操作
     */
    private static void UnInstallService(String serviceName) {
        try {
            // 执行安装服务的外部进程，并获取进程返回的结果映射
            Map<String, Object> map = executeProcess(backupExePath + " uninstall ", serviceName);
            // 检查进程返回码是否为0，以确定服务是否安装成功
            if ((Integer) map.get("code") == 0) {
                LoggerUtils.info("Service {} uninstalled successfully.", serviceName, map.get("msg"));
            } else {
                // 如果安装失败，记录失败信息和退出码
                LoggerUtils.warn("Failed to uninstall service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            // 如果发生IOException或InterruptedException，记录严重错误信息
            logs.log(Level.SEVERE, "Error uninstalling service: ", e);
        }
    }

    /**
     * 更新指定的服务
     *
     * @param serviceName 服务名称
     */
    private static void updateService(String serviceName) {
        try {
            // 执行更新服务的进程，传递必要的路径和参数
            Map<String, Object> map = executeProcess(backupExePath + " update ", serviceName);
            // 检查执行结果码是否为0，表示更新成功
            if ((Integer) map.get("code") == 0) {
                LoggerUtils.info("Service {} updated successfully.", serviceName, map.get("msg"));
            } else {
                // 如果结果码不为0，记录更新失败并显示错误信息
                LoggerUtils.warn("Failed to update service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            // 捕获IO异常或进程中断异常，并记录
            logs.log(Level.SEVERE, "Error updateing service: ", e);
        }
    }

    /**
     * 启动指定名称的服务
     *
     * @param serviceName 服务名称
     */
    private static void startService(String serviceName) {
        try {
            // 执行进程命令，尝试启动服务
            Map<String, Object> map = executeProcess(backupExePath + " start ", serviceName);
            // 检查执行结果
            if ((Integer) map.get("code") == 0) {
                // 如果返回码为0，表示服务启动成功
                LoggerUtils.info("Service {} started successfully.", serviceName, map.get("msg"));
            } else {
                // 如果返回码不为0，表示服务启动失败
                LoggerUtils.warn("Failed to start service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            // 捕获异常，记录日志
            logs.log(Level.SEVERE, "Error starting service: ", e);
        }
    }

    /**
     * 重启指定的服务
     *
     * @param serviceName 服务名称
     */
    private static void reStartService(String serviceName) {
        try {
            // 执行重启服务的进程
            Map<String, Object> map = executeProcess(backupExePath + " restart ", serviceName);
            // 检查重启服务的返回码
            if ((Integer) map.get("code") == 0) {
                LoggerUtils.info("Service {} restarted successfully.", serviceName);
            } else {
                LoggerUtils.warn("Failed to restart service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            logs.log(Level.SEVERE, "Error restarting service: ", e);
        }
    }

    /**
     * 停止指定的服务
     *
     * @param serviceName 服务名称
     */
    private static void stopService(String serviceName) {
        try {
            // 执行停止服务的命令，并获取命令执行结果
            Map<String, Object> map = executeProcess(backupExePath + " stop ", serviceName);

            // 检查命令执行状态码
            if ((Integer) map.get("code") == 0) {
                // 如果状态码为0，表示服务停止成功
                LoggerUtils.info("Service {} stopped successfully.", serviceName);
            } else {
                // 如果状态码不为0，表示服务停止失败
                LoggerUtils.warn("Failed to stop service {}: Exit code {}", serviceName, map.get("msg"));
            }
        } catch (IOException | InterruptedException e) {
            // 捕获异常，并记录错误信息
            logs.log(Level.SEVERE, "Error stopping service: ", e);
        }
    }

    /**
     * 执行系统命令并返回结果
     *
     * @param command     要执行的系统命令
     * @param serviceName 服务名称，用于日志记录
     * @return 包含命令输出和退出码的Map
     * @throws IOException          如果发生IO异常
     * @throws InterruptedException 如果线程被中断
     */
    private static Map<String, Object> executeProcess(String command, String serviceName) throws IOException, InterruptedException {
        Map<String, Object> result = new HashMap<>();
        try {


            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
            processBuilder.redirectErrorStream(true);

            // 执行命令安装服务
            Process process = processBuilder.start();

            int exitCode = process.waitFor();

            result.put("code", exitCode);
            result.put("msg", readProcessOutput(process));

        } catch (IOException | InterruptedException e) {
            result.put("code", -1);
            result.put("msg", e.getMessage());
        }

        return result;
    }

    // 辅助方法读取进程输出
    private static String readProcessOutput(Process process) throws IOException {
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        }
        return output.toString();
    }





}

